﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DBMethodsNamespace;
using ControlSesionNamespace;
using System.ComponentModel;
using ControlTareaPendienteNamespace;
using ControlLogNamespace;
using System.Threading;
using BackstageMusiciansFriend;
using System.IO;
using System.Net;
using System.Web.Script.Serialization;

namespace ControlModificacionDePreciosNamespace
{
    public class ModificacionDePreciosException : Exception
    {
        public ModificacionDePreciosException(string strMessage)
            : base(strMessage)
        {

        }
    }
    /// <summary>
    /// Summary description for ControlModificacionDePrecios
    /// </summary>
    public class ControlModificacionDePrecios
    {
        public const string MonedaDolarEstadounidense = "USD";
        public const string MonedaPesoArgentino = "ARS";
        public const string NombreTareaCalculo = "ModDePrecios";
        public const string NombreTareaImpacto = "ImpactoModDePrecios";

        #region Constant Properties
        public const string ConstIdleMode = "modoIdleTareasModDePrecios";
        public const string ConstIdleModeValueTRUE = "TRUE";
        public const string ConstIdleModeValueFALSE = "FALSE";
        #endregion

        List<ReglasExclusion> Reglas;
        bool AplicaCotizacion;
        double PorcentajeCotizacion;
        bool AplicaPorcentaje;
        double Porcentaje;
        bool AplicaIgualitario;
        double Igualitario;
        int Reintentos;
        int EspacioEntreIntentos;

        #region Constructor
        public ControlModificacionDePrecios()
        {
            Reglas = new List<ReglasExclusion>();
            AplicaCotizacion = false;
            AplicaIgualitario = false;
            AplicaPorcentaje = false;
        }
        #endregion
        #region Methods
        [DataObjectMethod(DataObjectMethodType.Select)]
        public IEnumerable<ReglasExclusion> ObtenerReglasDeExclusion()
        {
            DBMethods conn = new DBMethods();
            return conn.ObtenerReglasDeExclusion(ControlSesion.session(ControlSesion.UsuarioLogin));
        }
        [DataObjectMethod(DataObjectMethodType.Select)]
        public IEnumerable<ReglasExclusion> ObtenerReglasDeExclusionDebug()
        {
            var r1 = new ReglasExclusion { Conector = ReglasExclusion.Conector_And, Criterio = "LALA", IdRegla = "1", Tipo = ReglasExclusion.ReglaTipo_EmpiezaCon };
            var r2 = new ReglasExclusion { Conector = ReglasExclusion.Conector_And, Criterio = "LALO", IdRegla = "2", Tipo = ReglasExclusion.ReglaTipo_NoEsIgualA };

            List<ReglasExclusion> l = new List<ReglasExclusion> { r1, r2 };
            return l;
        }
        [DataObjectMethod(DataObjectMethodType.Update)]
        public void ModificarReglaDeExclusion(ReglasExclusion regla)
        {
            DBMethods conn = new DBMethods();
            conn.ModificarReglaDeExclusion(regla);
            return;
        }
        [DataObjectMethod(DataObjectMethodType.Delete)]
        public void BorrarReglaDeExclusion(ReglasExclusion regla)
        {
            DBMethods conn = new DBMethods();
            conn.BorrarReglaDeExclusion(regla);
            return;
        }


        private Total ObtenerCantidadDeItems(string urlParam)
        {
            string totalStr = String.Empty;
            Total total = new Total();
            try
            {
                HttpWebRequest requestForTotal = (HttpWebRequest)HttpWebRequest.Create(urlParam);

                requestForTotal.ContentType = "application/json;";
                requestForTotal.Accept = "application/json";
                requestForTotal.Method = "POST";
                WebResponse responseForTotal = requestForTotal.GetResponse();
                Stream streamForTotal = responseForTotal.GetResponseStream();
                StreamReader reader = new StreamReader(streamForTotal);

                totalStr = reader.ReadToEnd();
                totalStr = totalStr.Substring(totalStr.IndexOf("\"paging\":") + ("\"paging\":").Length, totalStr.IndexOf("\"results\":") - totalStr.IndexOf("\"paging\":") - ("\"paging\":").Length - 1);
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                total = serializer.Deserialize<Total>(totalStr);

                ControlLog.writeLog("[CalcularCantidadDeItemsTotales] Productos Totales = " + totalStr + " T=" + total.total + " O=" + total.offset + " L=" + total.limit);
            }
            catch (Exception ex)
            {
                throw new ModificacionDePreciosException("Error obteniendo cantidad de items totales del usuario: " + ex.Message);
            }

            return total;
        }
        private List<Item> ObtenerItems(string urlParam, out Total parcialParam)
        {
            string response = String.Empty;
            List<Item> items = new List<Item>();
            try
            {
                HttpWebRequest requestForTotal = (HttpWebRequest)HttpWebRequest.Create(urlParam);

                requestForTotal.ContentType = "application/json;";
                requestForTotal.Accept = "application/json";
                requestForTotal.Method = "POST";
                WebResponse responseForTotal = requestForTotal.GetResponse();
                Stream streamForTotal = responseForTotal.GetResponseStream();
                StreamReader reader = new StreamReader(streamForTotal);

                response = reader.ReadToEnd();
                string parcialStr = response.Substring(response.IndexOf("\"paging\":") + ("\"paging\":").Length, response.IndexOf("\"results\":") - response.IndexOf("\"paging\":") - ("\"paging\":").Length - 1);
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                parcialParam = serializer.Deserialize<Total>(parcialStr);
                string itemsStr = response.Substring(response.IndexOf("\"results\":") + ("\"results\":").Length, response.IndexOf("\"sort\":") - response.IndexOf("\"results\":") - ("\"results\":").Length - 1);
             //    ControlLog.writeLog("[ObtenerItems] Items = "+itemsStr);
                items = new JavaScriptSerializer().Deserialize<List<Item>>(itemsStr);
              //  ControlLog.writeLog("[ObtenerItems] Items = " + items.Count.ToString() + " id = " + items[0].id);
              //  ControlLog.writeLog("[ObtenerItems] Productos Totales = " + parcialStr + " T=" + parcialParam.total + " O=" + parcialParam.offset + " L=" + parcialParam.limit);
            }
            catch (Exception ex)
            {
                throw new ModificacionDePreciosException("Error obteniendo cantidad de items totales del usuario: " + ex.Message);
            }



            return items;
        }
        public void CalcularItemsAModificar(TareaPendiente tarea)
        {

            string sellerId = String.Empty;


            #region Etapa #0 - Levantar Seller Id
            try
            {
                tarea.actualizarEstado("Obteniendo ID de vendedor", "En curso");
                sellerId = ControlPublicacion.obtenerSellerId(ControlSesion.session(ControlSesion.AccessToken));
                ControlLog.writeLog("[CalcularItemsAModificar] Seller Id = " + sellerId);
            }
            catch (Exception ex)
            {
                throw new ModificacionDePreciosException("Error obteniendo el SELLER ID: " + ex.Message);
            }
            #endregion
            #region Etapa #1 - Levantar cantidad total de productos
            tarea.actualizarEstado("Obteniendo cantidad de items totales del usuario", "En curso");
            Total total = ObtenerCantidadDeItems("https://api.mercadolibre.com/sites/MLA/search?seller_id=" + sellerId + "&limit=0");
            #endregion
            try
            {
                #region Etapa #2 - Obtener todos los items del usuario          
                List<Item> items = new List<Item>();
                for (int offset = 0; offset < Convert.ToInt32(total.total); offset += 200)
                {
                    for (int reintentos = 0; reintentos < Reintentos; reintentos++)
                    {
                        try
                        {
                            Total parcial = new Total();


                            items.InsertRange(items.Count, ObtenerItems("https://api.mercadolibre.com/sites/MLA/search?seller_id=" + sellerId + "&limit=200&offset=" + offset.ToString(), out parcial));
                            tarea.actualizarEstado("Obteniendo " + parcial.offset + " items de " + parcial.total, "En curso");
                            //   offset += Math.Min(200,Convert.ToInt32(parcial.total) - offset);
                        }
                        catch (Exception innerEx)
                        {
                            ControlLog.writeLog("[CalcularItemsAModificar] Excepcion general en ciclo de busqueda de items: " + innerEx.Message);
                            ControlLog.writeLog("[CalcularItemsAModificar] Aguardando " + EspacioEntreIntentos.ToString() + " seg. para reintento" + (reintentos + 1).ToString());
                            tarea.actualizarEstado("Aguardando " + EspacioEntreIntentos.ToString() + " seg. para reintento" + (reintentos + 1).ToString(), "En curso");
                            Thread.Sleep(this.EspacioEntreIntentos * 1000);
                            ControlLog.writeLog("[CalcularItemsAModificar] Continuamos con reintento" + (reintentos + 1).ToString());
                            continue;

                        }

                        break;
                    }
                }

                ControlLog.writeLog("[CalcularItemsAModificar] Items leidos" + items.Count.ToString());

            #endregion
                #region Etapa #3 - Filtrado
                List<ReglasExclusion> reglas = (List<ReglasExclusion>)ObtenerReglasDeExclusion();
                List<Item> itemsFiltrados = new List<Item>();
                tarea.actualizarEstado("Filtrando " + items.Count.ToString() + " resultados", "En curso");
                         
                foreach (Item item in items)
                {
                    bool filtrosValidaItem = true;
                    foreach (ReglasExclusion regla in reglas)
                    {
                        if (!regla.ValidarItem(item.id, item.title))
                        {
                            filtrosValidaItem = false;
                            break;
                        }
                      
                    }

                    if (filtrosValidaItem)
                    {
                        itemsFiltrados.Add(item);
                    }
                }
                
                ControlLog.writeLog("[CalcularItemsAModificar] Items filtrados" + itemsFiltrados.Count.ToString());
                #endregion
                #region Etapa #4 Calcular modificaciones
                List<ItemParaActualizar> itemsParaActualizar = new List<ItemParaActualizar>();
                DBMethods conn = new DBMethods();
                conn.LimpiarItemsModificacionesDePreciosPendientes(ControlSesion.session(ControlSesion.UsuarioLogin));

                foreach (Item item in itemsFiltrados)
                {
                    ItemParaActualizar newItem = new ItemParaActualizar(item);
                    #region Accion #1 - Cotizacion porcentaje
                    if (item.currency_id == ControlModificacionDePrecios.MonedaPesoArgentino)
                    {
                        if (this.AplicaCotizacion)
                        {                            
                            newItem.AplicarCotizacion(this.PorcentajeCotizacion);
                        }
                    } 
                    #endregion
                    #region Accion #2 - Porcentaje
                    if (this.AplicaPorcentaje)
                    {
                        newItem.AplicarPorcentaje(this.Porcentaje);
                    } 
                    #endregion
                    #region Accion #3 - Igualitario
                    if (item.currency_id == ControlModificacionDePrecios.MonedaPesoArgentino)
                    {
                        if (this.AplicaIgualitario)
                        {
                            newItem.AplicarIgualitario(this.Igualitario);
                        }
                    } 
                    #endregion
                    conn.AgregarItemModificacionesDePreciosPendiente(newItem, ControlSesion.session(ControlSesion.UsuarioLogin));    
                }
                #endregion                            

            }
            catch (ThreadAbortException thAbEx)
            {
                ControlLog.writeLog("[CalcularItemsAModificar] Thread Abort Excepcion general " + thAbEx.Message);
            }
            catch (Exception ex)
            {
                ControlLog.writeLog("[CalcularItemsAModificar] Excepcion general " + ex.Message);
            }


        }
        public void ImpactarItemsPendientes(TareaPendiente tarea)
        {
            DBMethods conn = new DBMethods();
            List<ItemParaActualizar> itemsParaImpactar = new List<ItemParaActualizar>();
            #region Etapa #1 - Levantar los items pendientes de modificacion
            tarea.actualizarEstado("Obteniendo items pendientes de modificacion...", "En curso");                        
            itemsParaImpactar = conn.ObtenerItemsPendientesDeModificacion(ControlSesion.session(ControlSesion.UsuarioLogin));
            #endregion

            try
            {
                int indice = 0;
                foreach (ItemParaActualizar item in itemsParaImpactar)
                {

                    bool resultadoImpacto = false;
                    string error = String.Empty;
                    #region Etapa #2 - Impactar en ML
                    for (int reintentos = 0; reintentos < Reintentos; reintentos++)
                    {
                        //StringBuilder sb = new StringBuilder();
                        tarea.actualizarEstado("Impactando item " + indice.ToString() + " de " + itemsParaImpactar.Count.ToString()+" - Intento "+reintentos.ToString(), "En curso");                        
                        string strURL = " https://api.mercadolibre.com/items/" + item.ItemOriginal.id + "?access_token=" + ControlSesion.session(ControlSesion.AccessToken);

                        #region Filling HTML Header
                        ControlLog.writeLog("[ImpactarItemsPendientes] URL= " + strURL);
                        HttpWebRequest requestForUpdatingItem = (HttpWebRequest)HttpWebRequest.Create(strURL);
                        requestForUpdatingItem.Method = "PUT";
                        requestForUpdatingItem.ContentType = "application/json;";
                        requestForUpdatingItem.Accept = "application/json"; 
                        #endregion

                        try
                        {
                            #region Sending...		
                            using (StreamWriter writerForUpdatingItem = new StreamWriter(requestForUpdatingItem.GetRequestStream()))
                            {
                                ControlLog.writeLog("[ImpactarItemsPendientes] JSON to Send = " + "{ \"price\":\""+item.GetMonto()+"\" }");
                                writerForUpdatingItem.Write("{ \"price\":\""+item.GetMonto()+"\" }");

                            } 
	                        #endregion
                            #region Receiving...
                            HttpWebResponse response = (HttpWebResponse)requestForUpdatingItem.GetResponse();

                            Stream resStream = response.GetResponseStream();

                            StreamReader readerForDescription = new StreamReader(resStream);
                            string strJSONResponse = readerForDescription.ReadToEnd(); 
                            #endregion
                            #region Processing Results...
                            ControlLog.writeLog("[ImpactarItemsPendientes] Respuesta= " + strJSONResponse);
                            resultadoImpacto = true; 
                            #endregion
                            break;
                        }
                        catch (WebException webEx)
                        {
                            WebResponse responseForItemException = webEx.Response;
                            Stream streamForItemException = responseForItemException.GetResponseStream();
                            StreamReader readerException = new StreamReader(streamForItemException);
							string readerError = readerException.ReadToEnd();
							ControlLog.writeLog("[ImpactarItemsPendientes] WebException: " + readerError);
							error += "[Intento #" + reintentos.ToString().PadLeft(2, '0') + ": " + readerError + "]";
                            ControlLog.writeLog("[ImpactarItemsPendientes] Aguardando " + EspacioEntreIntentos.ToString() + " seg. para reintento" + (reintentos + 1).ToString());
                            tarea.actualizarEstado("Aguardando " + EspacioEntreIntentos.ToString() + " seg. para reintento" + (reintentos + 1).ToString(), "En curso");
                            Thread.Sleep(this.EspacioEntreIntentos * 1000);
                            ControlLog.writeLog("[ImpactarItemsPendientes] Continuamos con reintento" + (reintentos + 1).ToString());
                       
                        }
                        catch (Exception ex)
                        {
                            ControlLog.writeLog("[ImpactarItemsPendientes] Excepcion general= " + ex.Message);
							error += "[Intento #" + reintentos.ToString().PadLeft(2, '0') + ": " + ex.Message + "]";
                            ControlLog.writeLog("[ImpactarItemsPendientes] Aguardando " + EspacioEntreIntentos.ToString() + " seg. para reintento" + (reintentos + 1).ToString());
                            tarea.actualizarEstado("Aguardando " + EspacioEntreIntentos.ToString() + " seg. para reintento" + (reintentos + 1).ToString(), "En curso");
                            Thread.Sleep(this.EspacioEntreIntentos * 1000);
                            ControlLog.writeLog("[ImpactarItemsPendientes] Continuamos con reintento" + (reintentos + 1).ToString());
                      
                        }
                    }
                    #endregion
                    #region Etapa #3 - Actualizar estado en DB
                    if (resultadoImpacto == true)
                    {
                        conn.QuitarItemPendienteDeModificacionDePrecios(item, ControlSesion.session(ControlSesion.UsuarioLogin));
                        conn.AgregarItemModificacionesDePreciosFinalizadoOk(item, ControlSesion.session(ControlSesion.UsuarioLogin));
                    }
                    else
                    {
						item.Error = error.Replace(',','.');
                        conn.AgregarItemModificacionesDePreciosFinalizadoKo(item, ControlSesion.session(ControlSesion.UsuarioLogin), error);
                    }
                    #endregion
                    indice++;
                }

            }
            catch (ThreadAbortException thAbEx)
            {
                ControlLog.writeLog("[ImpactarItemsPendientes] Thread Abort Excepcion general " + thAbEx.Message);
            }
            catch (Exception ex)
            {
                ControlLog.writeLog("[ImpactarItemsPendientes] Excepcion general " + ex.Message);
            }

        }
        public void CargarReglas(System.Collections.IEnumerable iEnumerable)
        {
            Reglas = (List<ReglasExclusion>)iEnumerable;
        }
        public void CargarDiferenciaDeCotizacionAAplicar(string cotOriginalParam, string cotNuevaParam)
        {
            double cotOriginal;
            double cotNueva;

            this.AplicaCotizacion = true;

            try
            {
                cotOriginal = Convert.ToDouble(cotOriginalParam.Trim());
            }
            catch (Exception ex)
            {
                throw new ModificacionDePreciosException("No se puede convertir la cotizacion origen " + cotOriginalParam + " Mensaje: " + ex.Message);
            }
            try
            {
                cotNueva = Convert.ToDouble(cotNuevaParam.Trim());
            }
            catch (Exception ex)
            {
                throw new ModificacionDePreciosException("No se puede convertir la cotizacion nueva " + cotNuevaParam + " Mensaje: " + ex.Message);
            }

            this.PorcentajeCotizacion = cotNueva / cotOriginal;
            ControlLog.writeLog("[CargarDiferenciaDeCotizacionAAplicar] Porcentaje de cotizacion a aplicar = " +this.PorcentajeCotizacion.ToString());
        }
        public void CargarPorcentajeAAplicar(string porcentajeParam)
        {
            this.AplicaPorcentaje = true;

            try
            {
                this.Porcentaje = Convert.ToDouble(porcentajeParam.Trim())/100;
            }
            catch (Exception ex)
            {
                throw new ModificacionDePreciosException("No se puede convertir el porcentaje a aplicar " + porcentajeParam + " Mensaje: " + ex.Message);
            }
        }
        public void CargarIgualitarioAAplicar(string igualitarioParam)
        {
            this.AplicaIgualitario = true;
            try
            {
                this.Igualitario = Convert.ToDouble(igualitarioParam.Trim());
            }
            catch (Exception ex)
            {
                throw new ModificacionDePreciosException("No se puede convertir la cifra igualitaria a aplicar " + igualitarioParam + " Mensaje: " + ex.Message);
            }
        }
        public void ConfigurarReintentos(string reintentosParam, string espacioParam)
        {
            try
            {
                this.Reintentos = Convert.ToInt32(reintentosParam);
                this.EspacioEntreIntentos = Convert.ToInt32(espacioParam);
            }
            catch (Exception ex)
            {
                throw new ModificacionDePreciosException("No se puede configurar los reintentos R=" + reintentosParam + " E=" + espacioParam + " Mensaje: " + ex.Message);
            }
        }
        #endregion

        private class Total
        {
            public string total { get; set; }
            public string offset { get; set; }
            public string limit { get; set; }
        }
        public class Item
        {
            public string id { get; set; }
            public string price { get; set; }
            public string title { get; set; }
            public string currency_id { get; set; }
            public string permalink { get; set; }
           
        }
    
    }

    public class ItemParaActualizar
    {
        public ControlModificacionDePreciosNamespace.ControlModificacionDePrecios.Item ItemOriginal { get; set; }        
        public double Monto;
        public string FechaModificacion;
        public string Error;

        public ItemParaActualizar(ControlModificacionDePreciosNamespace.ControlModificacionDePrecios.Item item)
        {
            this.ItemOriginal = item;
            Monto = Convert.ToDouble(item.price.Replace('.',','));
            FechaModificacion = String.Empty;
            Error = String.Empty;
        }

        internal void AplicarCotizacion(double porcentajeParam)
        {

            this.AplicarPorcentaje(porcentajeParam);
        }

        internal void AplicarIgualitario(double igualitario)
        {
            Monto = Monto + igualitario;
        }

        internal void AplicarPorcentaje(double porcentajeParam)
        {
            //ControlLog.writeLog("[AplicarPorcentaje] Porcentaje = " + porcentajeParam.ToString());
            //ControlLog.writeLog("[AplicarPorcentaje] Monto viejo = " + monto.ToString());
            Monto = Monto * porcentajeParam;
            //ControlLog.writeLog("[AplicarPorcentaje] Monto nuevo = " + monto.ToString());
        }

        internal string GetMonto()
        {
            return Math.Round(this.Monto, 2).ToString().Replace(',', '.');
        }
    }

    public class ControlCalculoModificacionDePreciosAsyncHandler : System.Web.IHttpAsyncHandler
    {
        public static string strMensajeDeError;

        TareaPendiente objTareaARealizar;
        private AsyncTaskDelegate del;
        private AsyncTaskDelegate delTest;
        protected delegate void AsyncTaskDelegate(HttpContext context);
        ControlModificacionDePrecios objHandlerModificacionDePrecios;


        public ControlCalculoModificacionDePreciosAsyncHandler()
        {

        }
        public void ProcessRequest(HttpContext context)
        {
            try
            {
                ControlLog.writeLog("[ControlCalculoModificacionDePreciosAsyncHandler:ProcessRequestCalc] Calculando items a ser modificados");
                objHandlerModificacionDePrecios.CalcularItemsAModificar(this.objTareaARealizar);
                ControlLog.writeLog("[ControlCalculoModificacionDePreciosAsyncHandler:ProcessRequestCalc] Calculo finalizado OK");
            }
            catch (ModificacionDePreciosException modDePreciosEx)
            {
                ControlLog.writeLog("[ControlCalculoModificacionDePreciosAsyncHandler:ProcessRequestCalc] EXCEPCION de Calculo de Items de Modificacion De Precios: " + modDePreciosEx.Message);
                objTareaARealizar.actualizarEstado(modDePreciosEx.Message, "ERROR");
                Thread.Sleep(60000);
            }
            catch (Exception ex)
            {
                ControlLog.writeLog("[ControlCalculoModificacionDePreciosAsyncHandler:ProcessRequestCalc] Excepcion Procesando Tarea de Calculo de Items a modificar: " + ex.Message);
            }
        }
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object obj)
        {
            this.del = new AsyncTaskDelegate(ProcessRequest);
            objHandlerModificacionDePrecios = (ControlModificacionDePrecios)obj;
            AsyncCallback objCallBack = new AsyncCallback(callbackModDePrecios);
            objTareaARealizar = new TareaPendiente();
            objTareaARealizar.crearTarea(ControlSesion.session(ControlSesion.UsuarioLogin), ControlModificacionDePrecios.NombreTareaCalculo, "Calculando items en estado PUBLICADO" + System.DateTime.Now.ToString() + "]");
            return del.BeginInvoke(context, objCallBack, obj);


        }


        private void callbackModDePrecios(IAsyncResult ar)
        {
            try
            {
                this.EndProcessRequest(ar);
                //   objTareaARealizar.finalizar();
                objTareaARealizar.actualizarEstado("Tarea terminada", "END_VISIBLE");
                ControlLog.writeLog("[ControlCalculoModificacionDePreciosAsyncHandler:callbackModDePrecios] Liberando UNICA INSTANCIA...");
            }
            catch (ModificacionDePreciosException ex)
            {
                ControlLog.writeLog("[ControlCalculoModificacionDePreciosAsyncHandler:callbackModDePrecios] Excepcion finalizando tarea: " + ex.Message);
            }
        }

        public void EndProcessRequest(IAsyncResult ar)
        {
            try
            {
                ControlLog.writeLog("[ControlCalculoModificacionDePreciosAsyncHandler:EndProcessRequest] EndProcess llamado correctamente ");
                this.del.EndInvoke(ar);
            }
            catch (Exception ex)
            {
                ControlLog.writeLog("[ControlCalculoModificacionDePreciosAsyncHandler:EndProcessRequest] Excepcion en EndProcess = " + ex.Message);
                throw ex;
            }
        }

        public bool IsReusable { get { return true; } }
    }
    public class ControlImpactoModificacionDePreciosAsyncHandler : System.Web.IHttpAsyncHandler
    {
        public static string strMensajeDeError;

        TareaPendiente objTareaARealizar;
        private AsyncTaskDelegate del;
        private AsyncTaskDelegate delTest;
        protected delegate void AsyncTaskDelegate(HttpContext context);
        ControlModificacionDePrecios objHandlerModificacionDePrecios;


        public ControlImpactoModificacionDePreciosAsyncHandler()
        {

        }
        public void ProcessRequest(HttpContext context)
        {
            try
            {
                ControlLog.writeLog("[ControlImpactoModificacionDePreciosAsyncHandler:ProcessRequestCalc] Impactando items pendientes");
                objHandlerModificacionDePrecios.ImpactarItemsPendientes(this.objTareaARealizar);
                ControlLog.writeLog("[ControlImpactoModificacionDePreciosAsyncHandler:ProcessRequestCalc] Impacto finalizado OK");
            }
            catch (ModificacionDePreciosException modDePreciosEx)
            {
                ControlLog.writeLog("[ControlImpactoModificacionDePreciosAsyncHandler:ProcessRequestCalc] EXCEPCION de Impacto de Items pendientes de Modificacion De Precios: " + modDePreciosEx.Message);
                objTareaARealizar.actualizarEstado(modDePreciosEx.Message, "ERROR");
                Thread.Sleep(60000);
            }
            catch (Exception ex)
            {
                ControlLog.writeLog("[ControlImpactoModificacionDePreciosAsyncHandler:ProcessRequestCalc] Excepcion Procesando Tarea de Calculo de Items a modificar: " + ex.Message);
            }
        }
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object obj)
        {
            this.del = new AsyncTaskDelegate(ProcessRequest);
            objHandlerModificacionDePrecios = (ControlModificacionDePrecios)obj;
            AsyncCallback objCallBack = new AsyncCallback(callbackModDePrecios);
            objTareaARealizar = new TareaPendiente();
            objTareaARealizar.crearTarea(ControlSesion.session(ControlSesion.UsuarioLogin), ControlModificacionDePrecios.NombreTareaImpacto, "Impactando items pendientes... " + System.DateTime.Now.ToString() + "]");
            return del.BeginInvoke(context, objCallBack, obj);


        }


        private void callbackModDePrecios(IAsyncResult ar)
        {
            try
            {
                this.EndProcessRequest(ar);
                //   objTareaARealizar.finalizar();
                objTareaARealizar.actualizarEstado("Tarea terminada", "END_VISIBLE");
                ControlLog.writeLog("[ControlImpactoModificacionDePreciosAsyncHandler:callbackModDePrecios] Liberando UNICA INSTANCIA...");
            }
            catch (ModificacionDePreciosException ex)
            {
                ControlLog.writeLog("[ControlImpactoModificacionDePreciosAsyncHandler:callbackModDePrecios] Excepcion finalizando tarea: " + ex.Message);
            }
        }

        public void EndProcessRequest(IAsyncResult ar)
        {
            try
            {
                ControlLog.writeLog("[ControlImpactoModificacionDePreciosAsyncHandler:EndProcessRequest] EndProcess llamado correctamente ");
                this.del.EndInvoke(ar);
            }
            catch (Exception ex)
            {
                ControlLog.writeLog("[ControlImpactoModificacionDePreciosAsyncHandler:EndProcessRequest] Excepcion en EndProcess = " + ex.Message);
                throw ex;
            }
        }

        public bool IsReusable { get { return true; } }
    }



    public class ReglasExclusion
    {
        public const string ReglaTipo_CodigoIgualA = "COD. IGUAL";
        public const string ReglaTipo_CodigoNoIgualA = "COD. NO IGUAL";
        public const string ReglaTipo_EsIgualA = "IGUAL";
        public const string ReglaTipo_NoEsIgualA = "NO IGUAL";
        public const string ReglaTipo_EmpiezaCon = "EMPIEZA CON";
        public const string ReglaTipo_TerminaCon = "TERMINA CON";
        public const string ReglaTipo_Contiene = "CONTIENE";
        public const string ReglaTipo_NoContiene = "NO CONTIENE";

        public const string Conector_And = "Y";
        public const string Conector_Or = "O";

        public string Tipo { get; set; }
        public string Conector { get; set; }
        public string Criterio { get; set; }
        public string IdRegla { get; set; }

        public ReglasExclusion()
        {

        }
        public ReglasExclusion(string tipo, string conector, string criterio)
        {
            Tipo = tipo;
            Conector = conector;
            Criterio = criterio;
        }

        //public void CargarTipoDeRegla(string tipoParam)
        //{
        //    switch (tipoParam)
        //    {
        //        case ReglasExclusion.ReglaTipo_CodigoIgualA:
        //            Tipo = ReglaTipo.CodigoIgualA;
        //            break;
        //        case ReglasExclusion.ReglaTipo_CodigoNoIgualA:
        //            Tipo = ReglaTipo.CodigoNoIgualA;
        //            break;
        //        case ReglasExclusion.ReglaTipo_EsIgualA:
        //            Tipo = ReglaTipo.EsIgualA;
        //            break;
        //        case ReglasExclusion.ReglaTipo_NoEsIgualA:
        //            Tipo = ReglaTipo.NoEsIgualA;
        //            break;
        //        case ReglasExclusion.ReglaTipo_EmpiezaCon:
        //            Tipo = ReglaTipo.EmpiezaCon;
        //            break;
        //        case ReglasExclusion.ReglaTipo_TerminaCon:
        //            Tipo = ReglaTipo.TerminaCon;
        //            break;
        //        case ReglasExclusion.ReglaTipo_Contiene:
        //            Tipo = ReglaTipo.Contiene;
        //            break;
        //        case ReglasExclusion.ReglaTipo_NoContiene:
        //            Tipo = ReglaTipo.NoContiene;
        //            break;
        //        default:
        //            throw new Exception("No existe el tipo de regla " + tipoParam);
        //            break;
        //    }
        //}
        //public void CargarConector(string conectorParam)
        //{
        //    switch (conectorParam)
        //    {
        //        case ReglasExclusion.Conector_And:
        //            Conector = ConectorBooleano.ConectorAnd;
        //            break;
        //        case ReglasExclusion.Conector_Or:
        //            Conector = ConectorBooleano.ConectorOr;
        //            break;
        //        default:
        //            throw new Exception("No existe el conector " + conectorParam);
        //            break;
        //    }
        //}
        //public string ObtenerTipoDeRegla()
        //{
        //    switch (Tipo)
        //    {
        //        case ReglaTipo.CodigoIgualA:
        //            return ReglasExclusion.ReglaTipo_CodigoIgualA;                    
        //        case ReglaTipo.CodigoNoIgualA:
        //            return ReglasExclusion.ReglaTipo_CodigoNoIgualA;
        //        case ReglaTipo.Contiene:
        //            return ReglasExclusion.ReglaTipo_Contiene;   
        //        case ReglaTipo.EmpiezaCon:
        //            return ReglasExclusion.ReglaTipo_EmpiezaCon;   
        //        case ReglaTipo.EsIgualA:
        //            return ReglasExclusion.ReglaTipo_EsIgualA;  
        //        case ReglaTipo.NoContiene:
        //            return ReglasExclusion.ReglaTipo_NoContiene;  
        //        case ReglaTipo.NoEsIgualA:
        //            return ReglasExclusion.ReglaTipo_NoEsIgualA;  
        //        case ReglaTipo.TerminaCon:
        //            return ReglasExclusion.ReglaTipo_TerminaCon;  
        //        default:
        //            throw new Exception("No existe el tipo de regla " + Tipo.ToString());                    
        //    }

        //}
        //public string ObtenerConector()
        //{
        //    switch (Conector)
        //    {
        //        case ConectorBooleano.ConectorAnd:
        //            return ReglasExclusion.Conector_And;
        //        case ConectorBooleano.ConectorOr:
        //            return ReglasExclusion.Conector_Or;
        //        default:
        //            throw new Exception("Conector no reconocido " + Conector.ToString());
        //    }
        //}



        public bool ValidarItem(string idItemAValidarParam, string tituloItemAValidarParam)
        {
            bool boolReturn = false;
            ControlLog.writeLog("[ValidarItem] Criterio = {" + this.Criterio.Trim() + "} - Id = " + idItemAValidarParam.Trim() + " - T = " + tituloItemAValidarParam.Trim());
            string[] subCriterios = null;

            switch (this.Tipo)
            {
                case ReglasExclusion.ReglaTipo_CodigoIgualA:
                    {
                        #region Regla Codigo Igual A
                        subCriterios = this.Criterio.Split(new char[] { ',' });
                        // ControlLog.writeLog("[ValidarItem] ReglaTipo_CodigoIgualA >> Count: " + subCriterios.Length.ToString());

                        foreach (string subCriterio in subCriterios)
                        {
                            if (this.Conector == ReglasExclusion.Conector_And)
                            {
                                boolReturn = true;
                                if (subCriterio.Trim() != idItemAValidarParam.Trim())
                                {
                                    boolReturn = false;
                                    break;
                                }
                            }
                            else if (this.Conector == ReglasExclusion.Conector_Or)
                            {
                                if (subCriterio.Trim() == idItemAValidarParam.Trim())
                                {
                                    boolReturn = true;
                                    break;
                                }
                            }
                            else throw new NotImplementedException("No se implemento el conector " + this.Conector);
                            //       ControlLog.writeLog("[ValidarItem] ReglaTipo_CodigoIgualA >> Criterio: " + subCriterio);
                        }

                        return boolReturn;
                        // return (idItemAValidarParam.Trim() == this.Criterio.Trim()); 
                        #endregion
                    }
                case ReglasExclusion.ReglaTipo_CodigoNoIgualA:
                    {
                        #region Regla Codigo No Igual A
                        subCriterios = this.Criterio.Split(new char[] { ',' });
                        //    ControlLog.writeLog("[ValidarItem] ReglaTipo_CodigoNoIgualA >> Count: " + subCriterios.Length.ToString());

                        foreach (string subCriterio in subCriterios)
                        {
                            if (this.Conector == ReglasExclusion.Conector_And)
                            {
                                boolReturn = true;
                                if (subCriterio.Trim() == idItemAValidarParam.Trim())
                                {
                                    boolReturn = false;
                                    break;
                                }
                            }
                            else if (this.Conector == ReglasExclusion.Conector_Or)
                            {
                                if (subCriterio.Trim() != idItemAValidarParam.Trim())
                                {
                                    boolReturn = true;
                                    break;
                                }
                            }
                            else throw new NotImplementedException("No se implemento el conector " + this.Conector);
                            //     ControlLog.writeLog("[ValidarItem] ReglaTipo_CodigoNoIgualA >> Criterio: " + subCriterio);
                        }

                        return boolReturn;
                        //  return (idItemAValidarParam.Trim() != this.Criterio.Trim()); 
                        #endregion
                    }
                case ReglasExclusion.ReglaTipo_Contiene:
                    {
                        #region Regla Contiene
                        subCriterios = this.Criterio.Split(new char[] { ',' });
                        //   ControlLog.writeLog("[ValidarItem] ReglaTipo_Contiene >> Count: " + subCriterios.Length.ToString());

                        foreach (string subCriterio in subCriterios)
                        {
                            if (this.Conector == ReglasExclusion.Conector_And)
                            {
                                boolReturn = true;
                                if (!tituloItemAValidarParam.Trim().Contains(subCriterio.Trim()))
                                {
                                    boolReturn = false;
                                    break;
                                }
                            }
                            else if (this.Conector == ReglasExclusion.Conector_Or)
                            {
                                if (tituloItemAValidarParam.Trim().Contains(subCriterio.Trim()))
                                {
                                    boolReturn = true;
                                    break;
                                }
                            }
                            else throw new NotImplementedException("No se implemento el conector " + this.Conector);
                            //      ControlLog.writeLog("[ValidarItem] ReglaTipo_Contiene >> Criterio: " + subCriterio.Trim(new char[] { '"' }));
                        }

                        return boolReturn;
                        //   return tituloItemAValidarParam.Trim().Contains(this.Criterio.Trim()); 
                        #endregion
                    }
                case ReglasExclusion.ReglaTipo_EmpiezaCon:
                    {
                        #region Regla Empieza Con
                        subCriterios = this.Criterio.Split(new char[] { ',' });
                        //  ControlLog.writeLog("[ValidarItem] ReglaTipo_EmpiezaCon >> Count: " + subCriterios.Length.ToString());

                        foreach (string subCriterio in subCriterios)
                        {
                            if (this.Conector == ReglasExclusion.Conector_And)
                            {
                                boolReturn = true;
                                if (!tituloItemAValidarParam.Trim().StartsWith(subCriterio.Trim()))
                                {
                                    boolReturn = false;
                                    break;
                                }
                            }
                            else if (this.Conector == ReglasExclusion.Conector_Or)
                            {
                                if (tituloItemAValidarParam.Trim().StartsWith(subCriterio.Trim()))
                                {
                                    boolReturn = true;
                                    break;
                                }
                            }
                            else throw new NotImplementedException("No se implemento el conector " + this.Conector);
                            //      ControlLog.writeLog("[ValidarItem] ReglaTipo_EmpiezaCon >> Criterio: " + subCriterio.Trim(new char[] { '"' }));
                        }

                        return boolReturn;
                        //   return tituloItemAValidarParam.Trim().StartsWith(this.Criterio.Trim()); 
                        #endregion
                    }
                case ReglasExclusion.ReglaTipo_EsIgualA:
                    {
                        #region Regla Es Igual A
                        subCriterios = this.Criterio.Split(new char[] { ',' });
                        // ControlLog.writeLog("[ValidarItem] ReglaTipo_EsIgualA >> Count: " + subCriterios.Length.ToString());

                        foreach (string subCriterio in subCriterios)
                        {
                            if (this.Conector == ReglasExclusion.Conector_And)
                            {
                                boolReturn = true;
                                if (tituloItemAValidarParam.Trim() != subCriterio.Trim())
                                {
                                    boolReturn = false;
                                    break;
                                }
                            }
                            else if (this.Conector == ReglasExclusion.Conector_Or)
                            {
                                if (tituloItemAValidarParam.Trim() == subCriterio.Trim())
                                {
                                    boolReturn = true;
                                    break;
                                }
                            }
                            else throw new NotImplementedException("No se implemento el conector " + this.Conector);
                            //   ControlLog.writeLog("[ValidarItem] ReglaTipo_EsIgualA >> Criterio: " + subCriterio.Trim(new char[] { '"' }));
                        }

                        return boolReturn;
                        //   return (tituloItemAValidarParam.Trim() == this.Criterio.Trim()); 
                        #endregion
                    }
                case ReglasExclusion.ReglaTipo_NoContiene:
                    {
                        #region Regla No Contiene
                        subCriterios = this.Criterio.Split(new char[] { ',' });
                      //  ControlLog.writeLog("[ValidarItem] ReglaTipo_NoContiene >> Count: " + subCriterios.Length.ToString());

                        foreach (string subCriterio in subCriterios)
                        {
                            if (this.Conector == ReglasExclusion.Conector_And)
                            {
                                boolReturn = true;
                                if (tituloItemAValidarParam.Trim().Contains(subCriterio.Trim()))
                                {
                                    boolReturn = false;
                                    break;
                                }
                            }
                            else if (this.Conector == ReglasExclusion.Conector_Or)
                            {
                                if (!tituloItemAValidarParam.Trim().Contains(subCriterio.Trim()))
                                {
                                    boolReturn = true;
                                    break;
                                }
                            }
                            else throw new NotImplementedException("No se implemento el conector " + this.Conector);
                         //   ControlLog.writeLog("[ValidarItem] ReglaTipo_NoContiene >> Criterio: " + subCriterio.Trim(new char[] { '"' }));
                        }

                        return boolReturn;
                        //    return !(tituloItemAValidarParam.Trim().Contains(this.Criterio.Trim())); 
                        #endregion
                    }
                case ReglasExclusion.ReglaTipo_NoEsIgualA:
                    {
                        #region Regla No Es Igual A
                        subCriterios = this.Criterio.Split(new char[] { ',' });
                        //  ControlLog.writeLog("[ValidarItem] ReglaTipo_NoEsIgualA >> Count: " + subCriterios.Length.ToString());

                        foreach (string subCriterio in subCriterios)
                        {
                            if (this.Conector == ReglasExclusion.Conector_And)
                            {
                                boolReturn = true;
                                if (tituloItemAValidarParam.Trim() == subCriterio.Trim())
                                {
                                    boolReturn = false;
                                    break;
                                }
                            }
                            else if (this.Conector == ReglasExclusion.Conector_Or)
                            {
                                if (tituloItemAValidarParam.Trim() != subCriterio.Trim())
                                {
                                    boolReturn = true;
                                    break;
                                }
                            }
                            else throw new NotImplementedException("No se implemento el conector " + this.Conector);
                            //    ControlLog.writeLog("[ValidarItem] ReglaTipo_NoEsIgualA >> Criterio: " + subCriterio.Trim(new char[] { '"' }));
                        }

                        return boolReturn;
                        //    return (tituloItemAValidarParam.Trim() != this.Criterio.Trim()); 
                        #endregion
                    }
                case ReglasExclusion.ReglaTipo_TerminaCon:
                    {
                        #region Regla Termina Con
                        subCriterios = this.Criterio.Split(new char[] { ',' });
                        //  ControlLog.writeLog("[ValidarItem] ReglaTipo_TerminaCon >> Count: " + subCriterios.Length.ToString());

                        foreach (string subCriterio in subCriterios)
                        {
                            if (this.Conector == ReglasExclusion.Conector_And)
                            {
                                boolReturn = true;
                                if (tituloItemAValidarParam.Trim().StartsWith(subCriterio.Trim()))
                                {
                                    boolReturn = false;
                                    break;
                                }
                            }
                            else if (this.Conector == ReglasExclusion.Conector_Or)
                            {
                                if (!tituloItemAValidarParam.Trim().StartsWith(subCriterio.Trim()))
                                {
                                    boolReturn = true;
                                    break;
                                }
                            }
                            else throw new NotImplementedException("No se implemento el conector " + this.Conector);
                            //      ControlLog.writeLog("[ValidarItem] ReglaTipo_TerminaCon >> Criterio: " + subCriterio.Trim(new char[] { '"' }));
                        }

                        return boolReturn;
                        //    return tituloItemAValidarParam.Trim().EndsWith(this.Criterio.Trim()); 
                        #endregion
                    }
                default:
                    throw new ModificacionDePreciosException("No se encontro el tipo de regla " + this.Tipo);


            }
        }
    }
    public class ItemsDeModificacion
    {
        public string PrecioOriginal { get; set; }
        public string PrecioNuevo { get; set; }
        public string IdMl { get; set; }
        public string Link { get; set; }
        public string Titulo { get; set; }
        public TipoMoneda Moneda { get; set; }


    }

}